#include "logging.h"
//
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//
#include "utility.h"

enum LogLevel g_cxutil_logging_threshold =
    #ifdef CXUTIL_STARTING_LOG_LEVEL
        CXUTIL_STARTING_LOG_LEVEL
    #else
        #ifdef NDEBUG
            Warning
        #else
            Debug
        #endif
    #endif
    ;

static const char *logstrs[] = {
    NULL, "debug", "info", "warning", "error", "critical",
};

//__attribute__((noinline))
void cxutil_log(
        enum LogLevel level,
        char const *file,
        int line,
        char const *func,
        char const *msg)
{
    // prevent inlining due to lack of side effects in this function
    // this allows us to breakpoint on the level given
    //asm("");

    if (level < g_cxutil_logging_threshold)
        return;
    //fprintf(stderr, "%s: %s,%s(%d),%s: ",
    //        program_invocation_short_name, logstrs[level], file, line, func);
    fprintf(stderr, "%s,%s(%d),%s: %s\n",
            logstrs[level], file, line, func, msg);
}

void cxutil_logf(
        enum LogLevel level,
        char const *file,
        int line,
        char const *func,
        char const *fmt,
        ...)
{
    // save ourselves formatting a string that won't be used
    if (level < g_cxutil_logging_threshold) {
        return;
    }
    va_list ap;
    va_start(ap, fmt);
    int size = vsnprintf(VOID_CAST(char *, NULL), 0, fmt, ap);
    va_end(ap);
    char *str = VOID_CAST(decltype(str), alloca(size + 1));
    va_start(ap, fmt);
    verify(size == vsnprintf(str, size + 1, fmt, ap));
    va_end(ap);
    cxutil_log(level, file, line, func, str);
}
